#include "I2CDriver.h"
#include "..\System\F2806x_Device.h"

bool I2CDriver::InitI2C()
{
	EALLOW;
	/* Enable internal pull-up for the selected pins */
	GpioCtrlRegs.GPBPUD.bit.GPIO32 = 0;    // Enable pull-up for GPIO32 (SDAA)
	GpioCtrlRegs.GPBPUD.bit.GPIO33 = 0;	   // Enable pull-up for GPIO33 (SCLA)

	/* Set qualification for selected pins to asynch only */
	GpioCtrlRegs.GPBQSEL1.bit.GPIO32 = 3;  // Asynch input GPIO32 (SDAA)
    GpioCtrlRegs.GPBQSEL1.bit.GPIO33 = 3;  // Asynch input GPIO33 (SCLA)

	/* Configure SCI pins using GPIO regs*/
	GpioCtrlRegs.GPBMUX1.bit.GPIO32 = 1;   // Configure GPIO32 for SDAA operation
	GpioCtrlRegs.GPBMUX1.bit.GPIO33 = 1;   // Configure GPIO33 for SCLA operation
    EDIS;
    
    // Initialize I2C
	I2caRegs.I2CSAR = m_SAR;		// Slave address (7bit)
	I2caRegs.I2CPSC.all = 6;   // Prescaler - need 7-12 Mhz on module clk (80MHz/(6+1) = 11MHz)
	I2caRegs.I2CCLKL = 10;			// NOTE: must be non zero (400kHz total)
	I2caRegs.I2CCLKH = 10;			// NOTE: must be non zero
	
	I2caRegs.I2CIER.all = 0x00;		// Disable interrupts
	I2caRegs.I2CFFTX.all = 0x0000;	// Disable TX FIFOs
	I2caRegs.I2CFFRX.all = 0x0000;	// Disable RX FIFOs
	
	I2caRegs.I2CMDR.all = 0x0020;	// Take I2C out of reset, Stop I2C when suspended
		
	return true;
}

bool I2CDriver::WaitTransferDone(Uint16 codeToWait)
{
	while ( !(I2caRegs.I2CSTR.all & (codeToWait)) );
	// If a NACK occurred then SCL is held low and STP bit cleared
	if ( I2caRegs.I2CSTR.bit.NACK == 1 )
	{	
		I2caRegs.I2CMDR.all = 0; // reset 
		return false;
	}
	
	return true;
}

bool I2CDriver::Read4Bytes(Uint32* data)
{
	*data = 0;

	// Wait until the STP bit is cleared from any previous master communication.
	if (I2caRegs.I2CMDR.bit.STP == 1) return false; // fail
	if( I2caRegs.I2CSTR.bit.BB == 1 ) return false; // busy

	I2caRegs.I2CMDR.all = 0x0000; // disable I2C during configuration

	// Setup slave address (must be set in upper layer before this function is called!)
	I2caRegs.I2CSAR = m_SAR;

	// RECEIVE DATA
	I2caRegs.I2CCNT = 4;
	I2caRegs.I2CMDR.all = 0x2C20; // Set STT, STP, MST, IRS

	// MSB
	// Wait for "RRDY" flag to transmit data or "ARDY" if we get NACKed
	if( WaitTransferDone(0x0008|0x0004) == false ) return false;
	while( I2caRegs.I2CSTR.bit.RRDY == 0 );
	// read
	(*data) = I2caRegs.I2CDRR;
	(*data) = (*data) << 8; // shift left

	// mid-H
	// Wait for "RRDY" flag to transmit data or "ARDY" if we get NACKed
	if( WaitTransferDone(0x0008|0x0004) == false ) return false;
	while( I2caRegs.I2CSTR.bit.RRDY == 0 );
	// read
	(*data) += I2caRegs.I2CDRR;
	(*data) = (*data) << 8; // shift left

	// mid-L
	// Wait for "RRDY" flag to transmit data or "ARDY" if we get NACKed
	if( WaitTransferDone(0x0008|0x0004) == false ) return false;
	while( I2caRegs.I2CSTR.bit.RRDY == 0 );
	// read
	(*data) += I2caRegs.I2CDRR;
	(*data) = (*data) << 8; // shift left

	// LSB
	// Wait for "RRDY" flag to transmit data or "ARDY" if we get NACKed
	if( WaitTransferDone(0x0008|0x0004) == false ) return false;
	while( I2caRegs.I2CSTR.bit.RRDY == 0 );
	// read
	(*data) += I2caRegs.I2CDRR;

	// wait till transfer is compete (BB is zero and STP (stop) is cleared/transfered
	while(I2caRegs.I2CSTR.bit.BB == 1 );
	while(I2caRegs.I2CMDR.bit.STP == 1);

	return true;
}

bool I2CDriver::ReadReg16(Uint16 address, Uint16* data)
{
	*data = 0;
		
   	// Wait until the STP bit is cleared from any previous master communication.
   	if (I2caRegs.I2CMDR.bit.STP == 1) return false; // fail
	if( I2caRegs.I2CSTR.bit.BB == 1 ) return false; // busy
	
	I2caRegs.I2CMDR.all = 0x0000; // disable I2C during configuration
	
   	// Setup slave address (must be set in upper layer before this function is called!)
   	I2caRegs.I2CSAR = m_SAR;
	// write length (reg address)
   	I2caRegs.I2CCNT = 1;

	// TRANSMIT ADDRESS
   	// Setup data to send
   	I2caRegs.I2CMDR.all = 0x2620; // set STT, MST, TRX, IRS
	// Wait for "XRDY" flag to transmit data or "ARDY" if we get NACKed
	if( WaitTransferDone(0x0010|0x0004) == false ) return false;

	I2caRegs.I2CDXR = address; // address
	// Wait for "XRDY" flag to transmit data or "ARDY" if we get NACKed
	if( WaitTransferDone(0x0010|0x0004) == false ) return false;

	// RECEIVE DATA
	// wait for ARDY before beginning the read phase of the transaction
	while( I2caRegs.I2CSTR.bit.ARDY == 0 );
	I2caRegs.I2CCNT = 2;
   	I2caRegs.I2CMDR.all = 0x2C20; // Set STT, STP, MST, IRS
	
	// MSB
   	// Wait for "RRDY" flag to transmit data or "ARDY" if we get NACKed
   	if( WaitTransferDone(0x0008|0x0004) == false ) return false;
	while( I2caRegs.I2CSTR.bit.RRDY == 0 );
	// read
	(*data) = I2caRegs.I2CDRR;
	(*data) = (*data) << 8; // shift left
	
	// LSB
   	// Wait for "RRDY" flag to transmit data or "ARDY" if we get NACKed
   	if( WaitTransferDone(0x0008|0x0004) == false ) return false;
	while( I2caRegs.I2CSTR.bit.RRDY == 0 );
	// read
	(*data) += I2caRegs.I2CDRR; 	
	
	// wait till transfer is compete (BB is zero and STP (stop) is cleared/transfered
	while(I2caRegs.I2CSTR.bit.BB == 1 );
	while(I2caRegs.I2CMDR.bit.STP == 1);
	
	return true;	
}

bool I2CDriver::ReadReg24(Uint16 address, Uint32* data)
{
	*data = 0;
		
   	// Wait until the STP bit is cleared from any previous master communication.
   	if (I2caRegs.I2CMDR.bit.STP == 1) return false; // fail
	if( I2caRegs.I2CSTR.bit.BB == 1 ) return false; // busy
	
	I2caRegs.I2CMDR.all = 0x0000; // disable I2C during configuration
	
   	// Setup slave address (must be set in upper layer before this function is called!)
   	I2caRegs.I2CSAR = m_SAR;
	// write length (reg address)
   	I2caRegs.I2CCNT = 1;

	// TRANSMIT ADDRESS
   	// Setup data to send
   	I2caRegs.I2CMDR.all = 0x2620; // set STT, MST, TRX, IRS
	// Wait for "XRDY" flag to transmit data or "ARDY" if we get NACKed
	if( WaitTransferDone(0x0010|0x0004) == false ) return false;

	I2caRegs.I2CDXR = address; // address
	// Wait for "XRDY" flag to transmit data or "ARDY" if we get NACKed
	if( WaitTransferDone(0x0010|0x0004) == false ) return false;

	// RECEIVE DATA
	// wait for ARDY before beginning the read phase of the transaction
	while( I2caRegs.I2CSTR.bit.ARDY == 0 );
	I2caRegs.I2CCNT = 3;
   	I2caRegs.I2CMDR.all = 0x2C20; // Set STT, STP, MST, IRS
	
	// MSB
   	// Wait for "RRDY" flag to transmit data or "ARDY" if we get NACKed
   	if( WaitTransferDone(0x0008|0x0004) == false ) return false;
	while( I2caRegs.I2CSTR.bit.RRDY == 0 );
	// read
	(*data) = I2caRegs.I2CDRR;
	(*data) = (*data) << 8; // shift left
	
	// mid
   	// Wait for "RRDY" flag to transmit data or "ARDY" if we get NACKed
   	if( WaitTransferDone(0x0008|0x0004) == false ) return false;
	while( I2caRegs.I2CSTR.bit.RRDY == 0 );
	// read
	(*data) += I2caRegs.I2CDRR; 
	(*data) = (*data) << 8; // shift left	
	
	// LSB
   	// Wait for "RRDY" flag to transmit data or "ARDY" if we get NACKed
   	if( WaitTransferDone(0x0008|0x0004) == false ) return false;
	while( I2caRegs.I2CSTR.bit.RRDY == 0 );
	// read
	(*data) += I2caRegs.I2CDRR; 	
	
	// wait till transfer is compete (BB is zero and STP (stop) is cleared/transfered
	while(I2caRegs.I2CSTR.bit.BB == 1 );
	while(I2caRegs.I2CMDR.bit.STP == 1);
	
	return true;	
}

bool I2CDriver::ReadReg48Swapped(Uint16 startAddress, Uint16* data)
{
	*data = 0;
		
   	// Wait until the STP bit is cleared from any previous master communication.
   	if (I2caRegs.I2CMDR.bit.STP == 1) return false; // fail
	if( I2caRegs.I2CSTR.bit.BB == 1 ) return false; // busy
	
	I2caRegs.I2CMDR.all = 0x0000; // disable I2C during configuration
	
   	// Setup slave address (must be set in upper layer before this function is called!)
   	I2caRegs.I2CSAR = m_SAR;
	// write length (reg address)
   	I2caRegs.I2CCNT = 1;

	// TRANSMIT ADDRESS
   	// Setup data to send
   	I2caRegs.I2CMDR.all = 0x2620; // set STT, MST, TRX, IRS
	// Wait for "XRDY" flag to transmit data or "ARDY" if we get NACKed
	if( WaitTransferDone(0x0010|0x0004) == false ) return false;

	I2caRegs.I2CDXR = startAddress; // address
	// Wait for "XRDY" flag to transmit data or "ARDY" if we get NACKed
	if( WaitTransferDone(0x0010|0x0004) == false ) return false;

	// RECEIVE DATA
	// wait for ARDY before beginning the read phase of the transaction
	while( I2caRegs.I2CSTR.bit.ARDY == 0 );
	I2caRegs.I2CCNT = 6;
   	I2caRegs.I2CMDR.all = 0x2C20; // Set STT, STP, MST, IRS
	
	for(int i=0; i!=3; i++)
	{
	   	// Wait for "RRDY" flag to transmit data or "ARDY" if we get NACKed
	   	if( WaitTransferDone(0x0008|0x0004) == false ) return false;
		while( I2caRegs.I2CSTR.bit.RRDY == 0 );
		// read LSB
		data[i] = I2caRegs.I2CDRR;
		
	   	// Wait for "RRDY" flag to transmit data or "ARDY" if we get NACKed
	   	if( WaitTransferDone(0x0008|0x0004) == false ) return false;
		while( I2caRegs.I2CSTR.bit.RRDY == 0 );
		// read MSB
		data[i] += (I2caRegs.I2CDRR << 8); 	
	}
	
	
	// wait till transfer is compete (BB is zero and STP (stop) is cleared/transfered
	while(I2caRegs.I2CSTR.bit.BB == 1 );
	while(I2caRegs.I2CMDR.bit.STP == 1);
	
	return true;	
}

bool I2CDriver::ReadReg48(Uint16 startAddress, Uint16* data)
{
	*data = 0;

   	// Wait until the STP bit is cleared from any previous master communication.
   	if (I2caRegs.I2CMDR.bit.STP == 1) return false; // fail
	if( I2caRegs.I2CSTR.bit.BB == 1 ) return false; // busy

	I2caRegs.I2CMDR.all = 0x0000; // disable I2C during configuration

   	// Setup slave address (must be set in upper layer before this function is called!)
   	I2caRegs.I2CSAR = m_SAR;
	// write length (reg address)
   	I2caRegs.I2CCNT = 1;

	// TRANSMIT ADDRESS
   	// Setup data to send
   	I2caRegs.I2CMDR.all = 0x2620; // set STT, MST, TRX, IRS
	// Wait for "XRDY" flag to transmit data or "ARDY" if we get NACKed
	if( WaitTransferDone(0x0010|0x0004) == false ) return false;

	I2caRegs.I2CDXR = startAddress; // address
	// Wait for "XRDY" flag to transmit data or "ARDY" if we get NACKed
	if( WaitTransferDone(0x0010|0x0004) == false ) return false;

	// RECEIVE DATA
	// wait for ARDY before beginning the read phase of the transaction
	while( I2caRegs.I2CSTR.bit.ARDY == 0 );
	I2caRegs.I2CCNT = 6;
   	I2caRegs.I2CMDR.all = 0x2C20; // Set STT, STP, MST, IRS

	for(int i=0; i!=3; i++)
	{
	   	// Wait for "RRDY" flag to transmit data or "ARDY" if we get NACKed
	   	if( WaitTransferDone(0x0008|0x0004) == false ) return false;
		while( I2caRegs.I2CSTR.bit.RRDY == 0 );
		// read LSB
		data[i] = (I2caRegs.I2CDRR << 8);

	   	// Wait for "RRDY" flag to transmit data or "ARDY" if we get NACKed
	   	if( WaitTransferDone(0x0008|0x0004) == false ) return false;
		while( I2caRegs.I2CSTR.bit.RRDY == 0 );
		// read MSB
		data[i] += I2caRegs.I2CDRR;
	}


	// wait till transfer is compete (BB is zero and STP (stop) is cleared/transfered
	while(I2caRegs.I2CSTR.bit.BB == 1 );
	while(I2caRegs.I2CMDR.bit.STP == 1);

	return true;
}

bool I2CDriver::WriteReg8(Uint16 address, Uint16 data)
{
	// Wait until the STP bit is cleared from any previous master communication.
   	if (I2caRegs.I2CMDR.bit.STP == 1) return false; // fail
	if( I2caRegs.I2CSTR.bit.BB == 1 ) return false; // busy
	
	I2caRegs.I2CMDR.all = 0x0000; // disable I2C during configuration
	
   	// Setup slave address (must be set in upper layer before this function is called!)
   	I2caRegs.I2CSAR = m_SAR;
	// write length (reg address + data)
   	I2caRegs.I2CCNT = 2;

	// TRANSMIT ADDRESS + DATA
   	// Setup data to send
   	I2caRegs.I2CMDR.all = 0x2E20; // set STT, STP, MST, TRX, IRS
	// Wait for "XRDY" flag to transmit data or "ARDY" if we get NACKed
	if( WaitTransferDone(0x0010|0x0004) == false ) return false;

	I2caRegs.I2CDXR = address; // address
	// Wait for "XRDY" flag to transmit data or "ARDY" if we get NACKed
	if( WaitTransferDone(0x0010|0x0004) == false ) return false;

	I2caRegs.I2CDXR = data; // lower 8 bit of data
	// Wait for "XRDY" flag to transmit data or "ARDY" if we get NACKed
	if( WaitTransferDone(0x0010|0x0004) == false ) return false;

	// wait till transfer is compete (BB is zero and STP (stop) is cleared/transfered
	while(I2caRegs.I2CSTR.bit.BB == 1 );
	while(I2caRegs.I2CMDR.bit.STP == 1);
	
	return true;	
}
